﻿
using System.Drawing;
using System.Windows.Forms;
using Library.Util;
namespace Library.Winform.Draw {
	public class RectangleDraw : ObjectDraw {
		public const ushort LeftTop = 1;
		public const ushort CenterTop = 2;
		public const ushort RightTop = 3;
		public const ushort MidleRight = 4;
		public const ushort RightBottom = 5;
		public const ushort CenterBottom = 6;
		public const ushort LeftBottom = 7;
		public const ushort MidleLeft = 8;
		private static readonly ushort[] Handles = new[] { LeftTop, CenterTop, RightTop, MidleRight, RightBottom, CenterBottom, LeftBottom, MidleLeft };

		private int _minWidth;
		private int _minHeight;
		private Color _backGroundColor;

		protected Rectangle Rec;

		public int MinHeight {
			get { return _minHeight; }
			set {
				if (value < 0) value = -1;
				_minHeight = value;
			}
		}

		public int MinWidth {
			get {
				return _minWidth;
			}
			set {
				if (value < 0) value = -1;
				_minWidth = value;
			}
		}

		public Color BackgroundColor { get { return _backGroundColor; } set { _backGroundColor = value; } }

		public override void ReadFrom(System.IO.Stream stream) {
			int agrs;
			stream.Read(out _minWidth);
			stream.Read(out _minHeight);
			stream.Read(out agrs);
			Rec.X = agrs;
			stream.Read(out agrs);
			Rec.Y = agrs;
			stream.Read(out agrs);
			Rec.Width = agrs;
			stream.Read(out agrs);
			Rec.Height = agrs;
			_backGroundColor = ReadColorFromStream(stream);
			base.ReadFrom(stream);
		}

		public override void WriteTo(System.IO.Stream stream) {
			Normalize();
			stream.Write(_minWidth);
			stream.Write(_minHeight);
			stream.Write(Rec.X);
			stream.Write(Rec.Y);
			stream.Write(Rec.Width);
			stream.Write(Rec.Height);
			WriteColorToStream(stream, _backGroundColor);
			base.WriteTo(stream);
		}

		public RectangleDraw()
			: this(0, 0, 1, 1) {
		}
		public RectangleDraw(int x, int y, int width, int height) {
			Init(x, y, width, height);

		}

		public override ushort[] HandlePoints {
			get { return Handles; }
		}

		private void Init(int x, int y, int width, int height) {
			_minWidth = -1;
			_minHeight = -1;
			BackgroundColor = Color.FromKnownColor(KnownColor.Control);
			BuildRectange(x, y, width, height);
			ShadowLen = 5;
		}

		protected virtual void BuildRectange(int x, int y, int width, int height) {
			Rec.X = x;
			Rec.Y = y;
			if (MinWidth > -1)
				Rec.Width = width < MinWidth ? MinWidth : width;
			else {
				Rec.Width = width;
			}
			if (MinHeight > -1)
				Rec.Height = height < MinHeight ? MinHeight : height;
			else {
				Rec.Height = height;
			}

			//var newMaxPosition = GetPointFromHandle(RightBottom);
			//   var maxPositionChange = newMaxPosition.X != _maxPosition.X || newMaxPosition.Y != _maxPosition.Y;
			//  if (maxPositionChange) {
			// _maxPosition = newMaxPosition;
			//}
		}

		public int RecX { get { return Rec.X; } }

		public int RecY { get { return Rec.Y; } }

		public int RecWidth { get { return Rec.Width; } }

		public int RecHeight { get { return Rec.Height; } }

		public override Point MaxPosition {
			get {
				Normalize();
				return GetPointFromHandle(RightBottom);
			}
		}

		public override Point MinPosition {
			get {
				Normalize();
				return GetPointFromHandle(LeftTop);
			}
		}

		protected override Point GetLocation() {
			return GetPointFromHandle(LeftTop);
		}

		/// <summary>
		/// Draw rectangle
		/// </summary>
		/// <param name="g"></param>
		protected override void DrawMe(Graphics g) {
			var rec = RecWithScrollOffset;
			DrawShadow(g, rec);
			if (Enable)
				using (var brush = new SolidBrush(BackgroundColor)) {
					g.FillRectangle(brush, rec);
				} else {
				using (var brush = new SolidBrush(Color.FromKnownColor(KnownColor.ControlDark))) {
					g.FillRectangle(brush, rec);
				}
			}

			using (var pen = new Pen(PenColor, PenWidth)) {
				g.DrawRectangle(pen, rec);
			}
		}

		private void DrawShadow(Graphics g, Rectangle offsetRec) {
			if (ShadowLen > 0) {
				using (var brush = new SolidBrush(ShadowColor)) {
					ushort xOffset;
					ushort yOffset = xOffset = 0;
					if (offsetRec.Height > offsetRec.Width) {
						yOffset = ShadowLen;
					} else {
						xOffset = ShadowLen;
					}
					var yShadow = new Rectangle(offsetRec.Left + ShadowLen, offsetRec.Bottom, offsetRec.Width - xOffset, ShadowLen);
					g.FillRectangle(brush, yShadow);

					var xShadow = new Rectangle(offsetRec.Right, offsetRec.Top + ShadowLen, ShadowLen,
																	offsetRec.Height - yOffset);
					g.FillRectangle(brush, xShadow);
				}
			}
		}

		protected Rectangle RecWithScrollOffset {
			get {
				return new Rectangle(Rec.X - ScrollOffset.X, Rec.Y - ScrollOffset.Y, Rec.Width, Rec.Height);
			}
		}
		/// <summary>
		/// Check which edger container point.Result:
		///  0: No edge
		///  1: LeftTop
		///  2: Top edge
		///	 3: RightTop
		///  4: Right Edge
		///  5: RightBottom
		///  6: Bottom Edge
		///  7: LeftBottom
		///  8: Left edge	
		/// 
		/// </summary>
		/// <param name="point"></param>
		/// <returns>Value of egde</returns>
		public ushort BelongToEdge(Point point) {
			// check top
			if (Rec.Y == point.Y) {
				if (Rec.X == point.X) return LeftTop;
				if (Rec.Right == point.X) return RightTop;
				if (Rec.X < point.X && point.X < Rec.Right) return CenterTop;
			}
				// check bottom
			else if (Rec.Bottom == point.X) {
				if (Rec.X == point.X) return LeftBottom;
				if (Rec.Right == point.X) return RightBottom;
				if (Rec.X < point.X && point.X < Rec.Right) return CenterBottom;
			}
				// check left
			else if (Rec.X == point.X) {
				if (Rec.Y < point.Y && point.Y < Rec.Bottom) return MidleLeft;
			}
				// check right
			else if (Rec.Right == point.X) {
				if (Rec.Y < point.Y && point.Y < Rec.Bottom) return MidleRight;
			}

			return 0;
		}


		/// <summary>
		/// Move object
		/// </summary>
		/// <param name="deltaX"></param>
		/// <param name="deltaY"></param>
		protected override void MoveTo(int deltaX, int deltaY) {
			BuildRectange(Rec.X + deltaX, Rec.Y + deltaY, Rec.Width, Rec.Height);
		}

		protected override void MoveHandleTo(ushort pointHandler, Point newPoint) {
			int left = Rec.Left;
			int top = Rec.Top;
			int right = Rec.Right;
			int bottom = Rec.Bottom;
			switch (pointHandler) {
				case LeftTop:
					left = newPoint.X;
					top = newPoint.Y;
					break;
				case CenterTop:
					top = newPoint.Y;
					break;
				case RightTop:
					right = newPoint.X;
					top = newPoint.Y;
					break;
				case MidleRight:
					right = newPoint.X;
					break;
				case RightBottom:
					right = newPoint.X;
					bottom = newPoint.Y;
					break;
				case CenterBottom:
					bottom = newPoint.Y;
					break;
				case LeftBottom:
					left = newPoint.X;
					bottom = newPoint.Y;
					break;
				case MidleLeft:
					left = newPoint.X;
					break;
			}
			BuildRectange(left, top, right - left, bottom - top);
		}

		/// <summary>
		/// Get cursor for the handle
		/// </summary>
		/// <param name="pointHandler"></param>
		/// <returns></returns>
		public override Cursor GetHandleCursor(ushort pointHandler) {
			switch (pointHandler) {
				case LeftTop:
					return Cursors.SizeNWSE;
				case CenterTop:
					return Cursors.SizeNS;
				case RightTop:
					return Cursors.SizeNESW;
				case MidleRight:
					return Cursors.SizeWE;
				case RightBottom:
					return Cursors.SizeNWSE;
				case CenterBottom:
					return Cursors.SizeNS;
				case LeftBottom:
					return Cursors.SizeNESW;
				case MidleLeft:
					return Cursors.SizeWE;
				default:
					return Cursors.Default;
			}
		}

		public override bool ContainPoint(Point point) {
			return Rec.Contains(point);
		}
		public override Point GetPointFromHandle(ushort pointHandler) {
			var xCenter = Rec.X + Rec.Width / 2;
			var yCenter = Rec.Y + Rec.Height / 2;
			switch (pointHandler) {
				case LeftTop:
					return new Point(Rec.X, Rec.Y);
				case CenterTop:
					return new Point(xCenter, Rec.Y);
				case RightTop:
					return new Point(Rec.Right, Rec.Y);
				case MidleRight:
					return new Point(Rec.Right, yCenter);
				case RightBottom:
					return new Point(Rec.Right, Rec.Bottom);
				case CenterBottom:
					return new Point(xCenter, Rec.Bottom);
				case LeftBottom:
					return new Point(Rec.Left, Rec.Bottom);
				case MidleLeft:

					return new Point(Rec.Left, yCenter);
			}

			return base.GetPointFromHandle(pointHandler);
		}

		public override void Normalize() {
			var rec = NormalizedRectangle(Rec);
			BuildRectange(rec.X, rec.Y, rec.Width, rec.Height);
		}

		public override bool IntersectsWith(Rectangle rectangle) {
			return Rec.IntersectsWith(rectangle);
		}

		public override object Clone() {
			var clone = new RectangleDraw();
			FillOriginalTo(clone);
			return clone;
		}


		protected void FillOriginalTo(RectangleDraw rectangeDraw) {
			rectangeDraw._minHeight = _minHeight;
			rectangeDraw._minWidth = _minWidth;
			rectangeDraw.Rec = Rec;
			rectangeDraw._backGroundColor = _backGroundColor;
			base.FillOriginalTo(rectangeDraw);
		}


		#region Helper Functions

		public static Rectangle NormalizedRectangle(int x1, int y1, int x2, int y2) {
			if (x2 < x1) {
				int tmp = x2;
				x2 = x1;
				x1 = tmp;
			}

			if (y2 < y1) {
				int tmp = y2;
				y2 = y1;
				y1 = tmp;
			}

			return new Rectangle(x1, y1, x2 - x1, y2 - y1);
		}

		public static Rectangle NormalizedRectangle(Point p1, Point p2) {
			return NormalizedRectangle(p1.X, p1.Y, p2.X, p2.Y);
		}

		public static Rectangle NormalizedRectangle(Rectangle r) {
			return NormalizedRectangle(r.X, r.Y, r.X + r.Width, r.Y + r.Height);
		}

		#endregion
	}
}
